<?php
declare (strict_types=1);

namespace app\admin\controller\dev;

use app\admin\annotation\common\Auth;
use app\admin\controller\Admin;
use app\admin\model\admin\I18n as I18nModel;
use app\admin\model\dev\Action as ActionModel;
use app\admin\model\dev\Api as ApiModel;
use app\admin\model\dev\Menu as MenuModel;
use app\admin\service\admin\ConfigService;
use app\admin\service\admin\I18nService;
use app\admin\service\common\SortableService;
use app\admin\service\dev\PropService;
use app\admin\validate\dev\Action as ActionValidate;
use app\admin\service\dev\ActionService;
use app\admin\service\dev\MenuService;
use app\common\Constants;
use app\common\exception\BusinessException;
use app\common\facade\StrHelper;
use Raiseinfo\Tools;
use think\App;
use think\facade\Db;
use think\facade\Log;

class Action extends Admin
{

    #[Auth('dev:action:index')]
    public function index(): \think\response\Json
    {
        $params = $this->request->post();

        validate(ActionValidate::class)->scene('index')->check($params);

        $query = ActionModel::withPerms();

        $query->when(isset($params['id']), function ($query) use ($params) {
            $query->where('menu_id', '=', $params['id']);
        });

        $query->when(isset($params['keyword']), function ($query) use ($params) {
            $keyword = str_replace(['%', '_'], ['\%', '\_'], $params['keyword']);
            $query->where('name|remark', 'like', "%" . $keyword . "%");
        });

        $query->when(isset($params['status']), function ($query) use ($params) {
            $query->where('status', '=', $params['status']);
        });

        $order_by = sort_rules($params['order_by'] ?? 'sort|asc');
        $query->order($order_by);

        $page_size = $params['page_size'] ?? 10;
        $current_page = $params['current_page'] ?? 1;
        $list = $query->paginate(['list_rows' => $page_size, 'page' => $current_page])->toArray();

        $list['sort'] = $order_by;
        return $this->success(['data' => $list]);

    }


    /**
     * 新增
     * @return \think\response\Json
     */
    #[Auth('dev:action:add')]
    public function add(): \think\response\Json
    {
        try {
            $post = $this->request->post();
            validate(ActionValidate::class)->scene('add')->check($post);
            ActionService::addAction($post);
            return $this->success();
        } catch (\think\Exception\ValidateException $ve) {
            return $this->error(['message' => $ve->getMessage()]);
        } catch (\Exception $e) {
            throw $e;
        }
    }

    /**
     * 更新
     * @return \think\response\Json
     */
    #[Auth('dev:action:update')]
    public function update(): \think\response\Json
    {
        try {
            $post = $this->request->post();
            validate(ActionValidate::class)->scene('update')->check($post);
            ActionService::updateAction($post);
            return $this->success();
        } catch (\think\Exception\ValidateException $ve) {
            return $this->error(['message' => $ve->getMessage()]);
        } catch (\Exception $e) {
            throw $e;
        }
    }

    /**
     * 查询表单数据
     * @return \think\response\Json
     */
    #[Auth('dev:action:update')]
    public function getFormData(): \think\response\Json
    {

        $id = $this->request->param('id');
        if (!$id) {
            return $this->error(['message' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $result = ActionModel::find($id);
        if (!$result) {
            return $this->error(['message' => Constants::E_COMMON_RECORD_NOT_FOUND]);
        }
        if ($result['key']) {
            $result['translations'] = I18nModel::where('key', $result['key'])->column('value', 'lang_code');
        }
        return $this->success(['data' => $result]);

    }

    /**
     * 详情
     * @return \think\response\Json
     */
    #[Auth('dev:action:detail')]
    public function detail(): \think\response\Json
    {

        $id = $this->request->param('id');
        if (!$id) {
            return $this->error(['message' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $result = ActionModel::find($id);
        if (!$result) {
            return $this->error(['message' => Constants::E_COMMON_RECORD_NOT_FOUND]);
        }
        if ($result['key']) {
            $result['translations'] = I18nModel::where('key', $result['key'])->column('value', 'lang_code');
        }
        return $this->success(['data' => $result]);

    }


    /**
     * 删除
     * @return \think\response\Json
     */
    #[Auth('dev:action:delete')]
    public function delete(): \think\response\Json
    {
        $ids = $this->request->post('id/a');
        $ids = array_map('intval', $ids);
        $ids = array_filter($ids, function ($id) {
            return $id > 0;
        });
        if (empty($ids)) {
            return $this->error(['message' => Constants::E_COMMON_INVALID_PARAM]);
        }
        ActionService::deleteHandle($ids);
        return $this->success();

    }


    /**
     * 修改任意字段
     * @return \think\response\Json
     */
    #[Auth('dev:action:modify')]
    public function modify(): \think\response\Json
    {

        $post = $this->request->post();
        $keys = array_keys($post);
        $array = array_values(array_filter($keys, fn($v) => $v !== 'id'));
        $field = $array[0];
        if (!$post['id']) {
            throw new BusinessException(Constants::E_COMMON_INVALID_PARAM);
        }
        if (!in_array($field, ['remark', 'status', 'gen_php', 'gen_vue', 'auth_jwt', 'auth_sms', 'auth_img'])) {
            throw new BusinessException(Constants::E_COMMON_FORBIDDEN);
        }
        $model = ActionModel::find($post['id']);
        // 没有弹窗的，如果关闭生成代码，则不允许关闭
        if (!in_array($model['type'], ['update', 'add', 'detail'])) {
            if (
                !$model['config']['customize']['has_modal'] &&
                $field == 'gen_vue' &&
                $post[$field] == 0
            ) {
                throw new BusinessException(Constants::E_COMMON_GEN_VUE_NOT_TURN_OFF);
            }
        }

        if (!$model) {
            throw new BusinessException(Constants::E_COMMON_RECORD_NOT_FOUND);
        }
        $model[$field] = $post[$field];
        $result = $model->save();
        if (!$result) {
            throw new \Exception('更新状态失败');
        }
        return $this->success();

    }

    /**
     *  拖拽排序
     * @return \think\response\Json
     */
    #[Auth('dev:action:drag')]
    public function drag(): \think\response\Json
    {

        $fields = "newId,oldId,dragPos,orderBy";
        $data = $this->request->only(explode(',', $fields), 'post');
        SortableService::sort('dev_action', $data);
        return $this->success();

    }


    /**
     * 方法管理弹窗需要的初始化数据
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function initActionForm(): \think\response\Json
    {
        $menu_id = $this->request->post('menu_id');
        $app = $this->request->post('app');

        if ($app == 'admin') {
            // 字段所在菜单
            $data['menu_info'] = Db::name('dev_menu')->find($menu_id);
            // 当前菜单的权限前缀
            $data['permission_prefix'] = MenuService::getPermissionPrefix($menu_id);
        }
        if ($app == 'api') {
            // 字段所在菜单
            $data['menu_info'] = ApiModel::find($menu_id);
            $data['permission_prefix'] = '';
        }

        // 此菜单的字段列表，分为带主键的和不带主键的
        $data['fields'] = ActionService::fieldsList($menu_id); // hasId noId
        // 菜单的字段列表
        $data['menu_fields'] = ActionService::getMenuFieldList($menu_id);
        // 各个方法的默认设置
        $data['action_default'] = PropService::getActionTypeDefault();
        // 获取系统多语言类型列表
        $data['language_list'] = I18nService::getLangList();
        // 数据库连接列表
        $data['connection_list'] = MenuService::getConnectionList();


        return $this->success(['data' => $data]);
    }


    /**
     * 获取多语言键名
     * @return \think\response\Json
     */
    public function getLanguageKey(): \think\response\Json
    {
        $menu_id = $this->request->post('menu_id');
        $action = $this->request->post('action');

        if (empty($menu_id) || empty($action)) {
            throw new BusinessException(Constants::E_COMMON_INVALID_PARAM);
        }
        $key = ActionService::getActionLangKey($action, $menu_id);
        return $this->success(['data' => $key]);
    }


    /**
     * 根据菜单ID获得此菜单对应表的字段
     * @return \think\response\Json
     */
    public function getFields(): \think\response\Json
    {
        $id = $this->request->post('menu_id/d');
        if (!$id) {
            return $this->error(['msg' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $data = ActionService::fieldsNaleList($id);
        return $this->success(['data' => $data]);
    }

    /**
     * 根据菜单ID获得此菜单对应表的字段
     * @return \think\response\Json
     */
    public function getMenuFields(): \think\response\Json
    {
        $id = $this->request->post('menu_id/d');
        if (!$id) {
            return $this->error(['msg' => Constants::E_COMMON_INVALID_PARAM]);
        }
        $data = ActionService::getMenuFieldList($id);
        return $this->success(['data' => $data]);
    }


    /**
     * 查询业务菜单
     * @return \think\response\Json
     */
    public function getUserMenuOptions(): \think\response\Json
    {

        $menuList = Db::name('dev_menu')->alias('a')
            ->leftJoin('dev_menu b', 'a.pid=b.id')
            // ->field('a.id,concat(a.name,"(",concat(b.route_path,"/",a.route_path),")") as name,concat(b.route_path,"/",a.route_path) as route')
            ->field('a.id,concat(a.name,"(",a.route_path_full,")") as name,a.route_path_full as route')
            // ->where('a.is_sys', '=', 0)
            ->where('a.type', '=', 1)
            ->whereNull('a.delete_time')
            ->select()->toArray();
        return $this->success(['data' => $menuList]);

    }

    /**
     * 载入指定数据库连接的表的列表
     * @return \think\response\Json
     */
    public function getRelationTabls(): \think\response\Json
    {
        $conn = $this->request->post('conn');

        $tables = Db::name('dev_menu')
            ->field('table_name,name,id')
            ->where('type', 1)
            ->where('delete_time', null)
            ->where('status', 1)
            ->where('connect', $conn)
            ->whereNotLike('table_name', 'dev_%')
            ->order('sort', 'asc')
            ->select()->toArray();
        // 过滤系统字段
        $excludeTables = [];
        $result = [];
        foreach ($tables as $table) {
            // 过滤系统字段和空字段
            if (in_array($table['table_name'], $excludeTables) || empty($table['table_name'])) {
                continue;
            }
            $result[] = [
                'label' => $table['table_name'] . ' (' . $table['name'] . ')' ?: $table['table_name'], // 优先显示标题
                'value' => $table['table_name']
            ];
        }
        // 重置数组索引
        return $this->success(['data' => $result]);

    }

    /**
     * 载入指定数据库连接的，指定的表的，字段列表
     * @return \think\response\Json
     */
    public function getRelationFields(): \think\response\Json
    {
        $conn = $this->request->post('conn');
        $table = $this->request->post('table');

        $fields = Db::name('dev_field')
            ->alias('f')
            ->join('dev_menu m', 'f.menu_id = m.id')
            ->field('f.field,f.title')
            ->where('m.connect', $conn)
            ->where('m.table_name', $table)
            ->where('f.delete_time', null)
            ->where('f.status', 1)
            ->order('f.sort', 'asc')
            ->select()->toArray();
        // 过滤系统字段
        $excludeFields = [
            'create_time', 'update_time', 'delete_time',
            'create_id', 'update_id', 'delete_id', 'create_dept'
        ];
        $result = [];
        foreach ($fields as $field) {
            // 过滤系统字段和空字段
            if (in_array($field['field'], $excludeFields) || empty($field['field'])) {
                continue;
            }
            $result[] = [
                'label' => $field['field'] . ' (' . $field['title'] . ')' ?: $field['field'], // 优先显示标题
                'value' => $field['field']
            ];
        }
        return $this->success(['data' => $result]);

    }


    /**
     * 获得配置项的字典列表
     * @return \think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getConfigOptions(): \think\response\Json
    {
        $list = Db::name('admin_config')
            ->field('id as value,concat(name,"(",category,")") as label')
            ->where('status', 1)
            ->select();
        return $this->success(['data' => $list]);
    }


    /**
     * 载入各种字段类型的默认配置
     * @return \think\response\Json
     */
    public function getDefaultConfig()
    {
        $data = ActionService::defaultConfig();
        return $this->success(['data' => $data]);
    }

    public function getActionList()
    {
        $menu_id = $this->request->post('menu_id/d');

        $fieldList = ActionModel::where(['menu_id' => $menu_id])->order('sort', 'asc')->select()->toArray();
        return $this->success(['data' => $fieldList]);

    }




    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///


    /**
     * 根据action的信息生成此方法的权限代码
     * @param $data
     * @return string
     */
    private function getPermissionCode($data): string
    {
        $menuList = \app\admin\model\dev\Menu::field('id,pid,route_path as name')
            ->where('status', '=', 1)
            ->select()->toArray();
        $tools = new Tools();
        $parentNames = $tools->findParentNames($menuList, (int)$data['menu_id']);
        $menuNames = str_replace('-', ':', trim($parentNames, '/'));
        $permission = $menuNames . ':' . $data['method'];

        return strtolower($permission);
    }

    /**
     * 根据action的信息生成此方法的权限代码
     * @param $data
     * @return string
     */
    private function getActionUrl($data): string
    {
        $menuList = \app\admin\model\dev\Menu::field('id,pid,route_path as name')
            ->where('status', '=', 1)
            ->select()
            ->toArray();
        $menuInfo = \app\admin\model\dev\Menu::find((int)$data['menu_id']);
        $tools = new Tools();
        $parentNames = $tools->findParentNames($menuList, (int)$data['menu_id']);
        $menuNames = str_replace('-', '/', $parentNames);
        $url = '/' . $menuInfo->app . $menuNames . '/' . $data['method'];
        return strtolower($url);
    }

}
